A software application may include program code for performing two or more tasks. Although the tasks may exhibit various interdependencies, each task may generally be viewed as providing one or more dedicated functions. To optimize application efficiency and/or resource usage, the tasks may be executed by threads or within coroutines.
A thread is associated with a register set and an execution stack. A process is a container for one or more threads, each of which shares state information, memory address space, and other resources of the process. An operating system may schedule the threads of a multi-threaded process by running each thread during a dedicated processor timeslice. In addition, a multi-threaded process may control thread scheduling using timers, inter-thread signaling and/or other mechanisms.
Coroutines are associated with independent register sets and execution stacks. When a coroutine is called for the first time, execution begins at the beginning of its execution stack. Upon subsequent calls to the coroutine, execution resumes at a point from which the coroutine last called another coroutine. Accordingly, a coroutine may yield before its associated task is completed, and the task may be resumed by a subsequent call to the coroutine. A coroutine switch typically consumes less processor overhead than a thread switch, and may therefore provide faster task dispatching.
Coroutines cannot be properly used in conjunction with some programming languages or specific programming language features. For example, a task that is coded using C++ exception handling should not be executed within a coroutine since exception handling is not aware of coroutines. Such a C++ task may instead be executed using a dedicated thread. Conventional systems do not, however, provide cooperative scheduling of tasks executed by associated threads and tasks executed within coroutines. Accordingly, in order to cooperatively schedule the C++ task and a second task, the second task must be executed by an associated thread.
However, it may be desirable to execute the second task within a coroutine, particularly in a case that the second task is coded in a coroutine-compliant language and improved execution time is desired. More generally, systems are needed for efficiently scheduling tasks executed by associated threads and tasks executed within coroutines.